package cn.sell.bpmn.run.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.sell.bpmn.run.BpmRuntimeService;
import cn.sell.bpmn.run.entity.StartProcess;
import lombok.extern.log4j.Log4j2;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.runtime.ProcessInstance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.util.HashMap;
import java.util.Map;

/**
 * 1、流程运行服务
 * <p>
 * 2、对应的表
 * Execution   执行对象
 * 按流程定义的规则执行一次的过程.
 * 对应的表：
 * act_ru_execution： 正在执行的信息
 * act_hi_procinst：已经执行完的历史流程实例信息
 * act_hi_actinst：存放历史所有完成的活动
 * 1)操作数据库的act_ru_execution表,如果是用户任务节点，同时也会在act_ru_task添加一条记录
 *
 * <p>
 * ProcessInstance  流程实例
 * 特指流程从开始到结束的那个最大的执行分支，一个执行的流程中，流程实例只有1个。
 * 注意
 * （1）如果是单例流程，执行对象ID就是流程实例ID
 * （2）如果一个流程有分支和聚合，那么执行对象ID和流程实例ID就不相同
 * （3）一个流程中，流程实例只有1个，执行对象可以存在多个。
 *
 * <p>
 * Task 任务
 * 执行到某任务环节时生成的任务信息。
 * 对应的表：
 * act_ru_task：正在执行的任务信息
 * act_hi_taskinst：已经执行完的历史任务信息
 *
 * <p>
 * 流程变量
 * act_ru_variable
 * act_ge_bytearray
 * 通过JavaBean设置的流程变量，在act_ru_variable中存储的类型为serializable，变量真正存储的地方在act_ge_bytearray中。
 */
@Log4j2
@Service
//@Transactional
public class BpmRuntimeServiceImpl implements BpmRuntimeService {

    @Autowired
    private RuntimeService runtimeService; // 与正在执行的流程实例和执行对象相关的service

    public ProcessInstance startProcessInstance(StartProcess startProcess) throws Exception {
        String variablesName = "processVariables";
        String userId = "userId";
        verification(startProcess);
        ProcessInstance processInstance = null;

        Map<String, Object> startMap = new HashMap<String, Object>();
        startMap.put("userId", userId); // buside 业务说明

        if (StrUtil.isNotBlank(startProcess.getProcessInstanceByKey())) {
            processInstance = runtimeService
                    .startProcessInstanceByKey(startProcess.getProcessInstanceByKey(), startProcess.getBusinessKey(),startMap);
        } else if (StrUtil.isNotBlank(startProcess.getProcessInstanceById())) {
            processInstance = runtimeService
                    .startProcessInstanceById(startProcess.getProcessInstanceById(), startProcess.getBusinessKey(),startMap);
        } else {
            throw new Exception("processInstanceByKey and processInstanceById is not null At the same time [ 不能同时为空 ]");
        }
        runtimeService.setVariable(processInstance.getId(), variablesName, startProcess.getProcessVariables());

        log.info("流程实例id：" + processInstance.getId());
        log.info("当前活动id：" + processInstance.getActivityId());
        log.info("流程定义id：" + processInstance.getProcessDefinitionId());
        return processInstance;
    }

//    public void setVariable(String processInstanceId,Map<String ,Object> variables){
////        Execution execution = runtimeService.createExecutionQuery()
////                .processInstanceId(processInstanceId).activityId(tkdfid).singleResult();
//        ProcessInstance processInstance = queryProcessStatus(processInstanceId);
//        processInstance.getActivityId();
//        runtimeService.setVariable(processInstanceId, execution.getId(),variables);
//    }

    /**
     * 启动信息校验
     * @param startProcess
     */
    private void verification(StartProcess startProcess) throws Exception {
        if (StrUtil.isBlank(startProcess.getProcessInstanceByKey()) && StrUtil.isBlank(startProcess.getProcessInstanceById())) {
            throw new Exception("processInstanceByKey and processInstanceById is not null At the same time [ 不能同时为空 ]");
        }
        Assert.notNull(startProcess.getBusinessKey(), "businessKey is not null [ 业务编码不能为空 ]");
        if(BeanUtil.isEmpty(startProcess.getProcessVariables())){
            throw new Exception("processVariables is not null [ 流程变量不能为空 ]");
        }
    }

    /**
     * 查询流程状态
     */
    public ProcessInstance queryProcessStatus(String processInstanceId){
        ProcessInstance processInstance = runtimeService
                .createProcessInstanceQuery() // 创建流程实例查询，查询正在执行的流程实例
                .processInstanceId(processInstanceId) // 按照流程实例id查询
                .singleResult();// 返回唯一结果集
        if(processInstance !=null){
            log.info("getId：" + processInstance.getId());
            log.info("getName：" + processInstance.getName());
            log.info("getProcessInstanceId：" + processInstance.getProcessInstanceId());
            log.info("getProcessDefinitionId：" + processInstance.getProcessDefinitionId());
            log.info("getProcessDefinitionKey：" + processInstance.getProcessDefinitionKey());
            log.info("getBusinessKey：" + processInstance.getBusinessKey());
            log.info("getDeploymentId：" + processInstance.getDeploymentId());
            log.info("getDescription：" + processInstance.getDescription());
            log.info("getProcessDefinitionName：" + processInstance.getProcessDefinitionName());
            log.info("getActivityId：" + processInstance.getActivityId());
        }else{
            log.info("流程实例已经结束");
        }
        return processInstance;
    }
}
